package com.tsy.server.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tsy.server.common.PageResult;
import com.tsy.server.common.page.ResultCode;
import com.tsy.server.component.redis.RedisKeyConstant;
import com.tsy.server.system.entity.Organization;
import com.tsy.server.system.entity.Role;
import com.tsy.server.system.entity.User;
import com.tsy.server.system.entity.UserOrganization;
import com.tsy.server.system.entity.dto.*;
import com.tsy.server.system.entity.vo.*;
import com.tsy.server.system.mapper.OrganizationMapper;
import com.tsy.server.system.mapper.RoleMapper;
import com.tsy.server.system.mapper.UserMapper;
import com.tsy.server.system.mapper.UserOrganizationMapper;
import com.tsy.server.component.security.CustomUserDetails;
import com.tsy.server.component.security.SecurityUtils;
import com.tsy.server.system.service.EmailService;
import com.tsy.server.system.service.UserService;
import com.tsy.server.common.util.JwtTokenUtil;
import com.tsy.server.common.util.RedisUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * 用户服务实现类
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserOrganizationMapper userOrganizationMapper;

    @Autowired
    private OrganizationMapper organizationMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private EmailService emailService;

    @Value("${jwt.tokenHead}")
    private String tokenHead;

    @Value("${jwt.expiration}")
    private Long expiration;

    /**
     * 用户注册
     *
     * @param registerDTO 注册信息
     * @return 是否成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean register(UserRegisterDTO registerDTO) {
        // 验证两次密码是否一致
        if (!registerDTO.getPassword().equals(registerDTO.getConfirmPassword())) {
            throw new RuntimeException("两次密码不一致");
        }

        // 验证用户名是否已存在
        if (getUserByUsername(registerDTO.getUsername()) != null) {
            throw new RuntimeException(ResultCode.USERNAME_EXISTS.getMessage());
        }

        // 验证邮箱是否已存在
        if (getUserByEmail(registerDTO.getEmail()) != null) {
            throw new RuntimeException(ResultCode.EMAIL_EXISTS.getMessage());
        }

        // 验证邮箱验证码
        if (!emailService.verifyCode(registerDTO.getEmail(), registerDTO.getVerificationCode())) {
            throw new RuntimeException(ResultCode.EMAIL_CODE_ERROR.getMessage());
        }

        // 创建用户
        User user = new User();
        user.setUsername(registerDTO.getUsername());
        user.setPassword(passwordEncoder.encode(registerDTO.getPassword()));
        user.setEmail(registerDTO.getEmail());
        user.setNickname(registerDTO.getNickname() != null ? registerDTO.getNickname() : registerDTO.getUsername());
        user.setStatus(1); // 启用状态

        return userMapper.insert(user) > 0;
    }

    /**
     * 用户登录
     *
     * @param loginDTO 登录信息
     * @return 登录结果
     */
    @Override
    public UserLoginVO login(UserLoginDTO loginDTO) {
        // 进行身份验证
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
                loginDTO.getUsername(), loginDTO.getPassword());
        Authentication authentication = authenticationManager.authenticate(authenticationToken);
        SecurityContextHolder.getContext().setAuthentication(authentication);

        // 生成JWT令牌
        CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal();
        String token = jwtTokenUtil.generateToken(userDetails);

        // 检查用户是否已在其他设备登录
        String tokenKey = RedisKeyConstant.buildUserTokenKey(userDetails.getUsername());
        if (redisUtil.hasKey(tokenKey)) {
            // 删除旧的token
            String oldToken = (String) redisUtil.get(tokenKey);
            redisUtil.delete(RedisKeyConstant.buildLoginTokenKey(oldToken));
        }

        // 将token存入Redis，用于单点登录控制
        redisUtil.set(tokenKey, token, expiration);
        redisUtil.set(RedisKeyConstant.buildLoginTokenKey(token), userDetails, expiration);

        // 更新用户最后登录时间
        User user = userDetails.getUser();
        user.setLastLoginTime(LocalDateTime.now());
        userMapper.updateById(user);

        // 构建返回结果
        UserInfoVO userInfoVO = new UserInfoVO();
        BeanUtils.copyProperties(user, userInfoVO);

        // 查询用户权限
        // todo 是否放入缓存
        RolePermissionVO rolePermissionVO = null;
        if (user.getCurrentOrgId() != null) {
            LambdaQueryWrapper<UserOrganization> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(UserOrganization::getUserId, user.getId());
            queryWrapper.eq(UserOrganization::getOrgId, user.getCurrentOrgId());
            UserOrganization userOrganization = userOrganizationMapper.selectOne(queryWrapper);
            if (userOrganization != null) {
                rolePermissionVO = roleMapper.getPermissionsByRoleId(userOrganization.getRoleId());
                userInfoVO.setRolePermissions(rolePermissionVO);
            }
        }

        // 获取workSpaceId
        Organization organization = organizationMapper.selectById(user.getCurrentOrgId());

        return UserLoginVO.builder()
                .token(token)
                .tokenHead(tokenHead)
                .currentOrgId(user.getCurrentOrgId())
                .workSpaceId(organization.getOrgId())
                .userInfo(userInfoVO)
                .build();
    }

    /**
     * 根据用户名获取用户信息
     *
     * @param username 用户名
     * @return 用户信息
     */
    @Override
    public User getUserByUsername(String username) {
        return userMapper.selectOne(new LambdaQueryWrapper<User>()
                .eq(User::getUsername, username));
    }

    /**
     * 根据邮箱获取用户信息
     *
     * @param email 邮箱
     * @return 用户信息
     */
    @Override
    public User getUserByEmail(String email) {
        return userMapper.selectOne(new LambdaQueryWrapper<User>()
                .eq(User::getEmail, email));
    }

    /**
     * 获取当前登录用户信息
     *
     * @return 用户信息
     */
    @Override
    public UserInfoVO getCurrentUserInfo() {
        // 获取当前登录用户
        User currentUser = SecurityUtils.getCurrentUser();
        // 转换为VO对象
        UserInfoVO userInfoVO = new UserInfoVO();
        BeanUtils.copyProperties(currentUser, userInfoVO);
        // 查询用户权限
        // todo 是否放入缓存
        RolePermissionVO rolePermissionVO = null;
        if (currentUser.getCurrentOrgId() != null) {
            LambdaQueryWrapper<UserOrganization> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(UserOrganization::getUserId, currentUser.getId());
            queryWrapper.eq(UserOrganization::getOrgId, currentUser.getCurrentOrgId());
            UserOrganization userOrganization = userOrganizationMapper.selectOne(queryWrapper);
            if (userOrganization != null) {
                rolePermissionVO = roleMapper.getPermissionsByRoleId(userOrganization.getRoleId());
                userInfoVO.setRolePermissions(rolePermissionVO);
            }
        }
        return userInfoVO;
    }

    /**
     * 退出登录
     *
     * @param token 令牌
     * @return 是否成功
     */
    @Override
    public boolean logout(String token) {
        // 从token中获取用户名
        String username = jwtTokenUtil.getUsernameFromToken(token);
        if (username != null) {
            // 删除Redis中的token
            redisUtil.delete(RedisKeyConstant.buildUserTokenKey(username));
            redisUtil.delete(RedisKeyConstant.buildLoginTokenKey(token));
            return true;
        }
        return false;
    }

    /**
     * 发送邮箱验证码
     *
     * @param email 邮箱
     * @return 是否成功
     */
    @Override
    public boolean sendVerificationCode(String email) {
        return emailService.sendVerificationCode(email);
    }
    
    @Override
    public String verifyEmailCode(VerifyCodeDTO verifyCodeDTO) {
        boolean verifyCode = emailService.verifyCode(verifyCodeDTO.getEmail(), verifyCodeDTO.getCode());
        if (!verifyCode) {
            throw new RuntimeException(ResultCode.EMAIL_CODE_ERROR.getMessage());
        }
        // 生成临时restPwdToken
        String restPwdToken = UUID.randomUUID().toString();
        // 查询用户信息
        User user = getUserByEmail(verifyCodeDTO.getEmail());
        if (user == null) {
            throw new RuntimeException("该邮箱用户不存在");
        }
        // 放入缓存-5分钟
        redisUtil.set(RedisKeyConstant.buildRestPwdTokenKey(restPwdToken), user, 5 * 60);
        return restPwdToken;
    }
    
    @Override
    public void resetPassword(ResetPasswordDTO resetPasswordDTO) {

        // 验证两次密码是否一致
        if (!resetPasswordDTO.getNewPassword().equals(resetPasswordDTO.getConfirmNewPassword())) {
            throw new RuntimeException("两次密码不一致");
        }
        
        // 验证邮箱是否存在
        String tokenKey = RedisKeyConstant.buildRestPwdTokenKey(resetPasswordDTO.getRestPwdToken());
        User user = (User) redisUtil.get(tokenKey);
        if (user == null) {
            throw new RuntimeException("临时令牌有误或已过期");
        }
        // 更新密码
        User userUpdate = new User();
        userUpdate.setId(user.getId());
        userUpdate.setPassword(passwordEncoder.encode(resetPasswordDTO.getNewPassword()));
        // 更新数据库
        userMapper.updateById(userUpdate);
        // 删除缓存
        redisUtil.delete(tokenKey);
    }

    @Override
    public RolePermissionVO switchOrg(Long currentOrgId) {
        // 查询用户是否在该组织
        Long currentUserId = SecurityUtils.getCurrentUserId();
        LambdaQueryWrapper<UserOrganization> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(UserOrganization::getUserId, currentUserId);
        queryWrapper.eq(UserOrganization::getOrgId, currentOrgId);
        UserOrganization userOrganization = userOrganizationMapper.selectOne(queryWrapper);
        if (userOrganization == null) {
            throw new RuntimeException("该用户不在当前组织下");
        }
        // 设置用户当前组织
        User user = new User();
        user.setId(currentUserId);
        user.setCurrentOrgId(currentOrgId);
        userMapper.updateById(user);

        // 更新缓存
        CustomUserDetails userDetails = SecurityUtils.getCurrentUserDetails();
        assert userDetails != null;
        // 获取角色key
        String roleKey = userMapper.getUserCurrentOrgRoleKey(currentUserId, currentOrgId);
        userDetails.setRoleKey(roleKey);
        // 获取workSpaceId
        Organization organization = organizationMapper.selectById(currentOrgId);
        userDetails.setWorkspaceId(organization.getOrgId());
        User detailsUser = userDetails.getUser();
        detailsUser.setCurrentOrgId(currentOrgId);
        // 获取token
        String token = (String)redisUtil.get(RedisKeyConstant.buildUserTokenKey(userDetails.getUsername()));
        redisUtil.set(RedisKeyConstant.buildLoginTokenKey(token), userDetails, expiration);

        // 查找用户组织角色权限
        RolePermissionVO permissions = roleMapper.getPermissionsByRoleId(userOrganization.getRoleId());
        permissions.setWorkspaceId(organization.getOrgId());
        return permissions;
    }

    @Override
    public Page<UserListVO> getOrgUserList(UserVO userVO) {
        Page<UserListVO> page = PageResult.buildPage();
        Long orgId = SecurityUtils.getCurrentOrgId();
        return userMapper.selectOrgUserList(page, orgId, userVO);
    }

    @Override
    public void delOrgUser(Long userId) {
        Long currentUserId = SecurityUtils.getCurrentUserId();
        if (userId.equals(currentUserId)) {
            throw new RuntimeException("不能从组织删除自己");
        }
        Long orgId = SecurityUtils.getCurrentOrgId();
        LambdaQueryWrapper<UserOrganization> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(UserOrganization::getUserId, userId);
        queryWrapper.eq(UserOrganization::getOrgId, orgId);
        userOrganizationMapper.delete(queryWrapper);
    }

    @Override
    public void updateOrgUser(UserOrganizationDTO dto) {
        Long currentUserId = SecurityUtils.getCurrentUserId();
        // 检查当前用户是否在尝试修改自己的角色信息
        if (dto.getUserId().equals(currentUserId)) {
            // 如果是修改自己的角色，确保角色ID是超级管理员（1L）
            if (dto.getRoleId() != 1L) {
                throw new RuntimeException("不能修改自己的角色信息");
            }
        } else {
            // 如果是修改他人的角色，确保角色存在且不是超级管理员
            Role role = roleMapper.selectById(dto.getRoleId());
            if (role == null || role.getId() == 1L) {
                throw new RuntimeException("角色不存在或不能使用该角色");
            }
        }

        userOrganizationMapper.update(null, Wrappers.<UserOrganization>lambdaUpdate()
                .set(UserOrganization::getRoleId, dto.getRoleId())
                .set(UserOrganization::getUserOrgName, dto.getUserOrgName())
                .eq(UserOrganization::getUserId, dto.getUserId())
                .eq(UserOrganization::getOrgId, SecurityUtils.getCurrentOrgId()));
    }

    @Override
    public void batchAddOrgUser(List<UserOrganizationDTO> list) {
        List<UserOrganization> userOrgList = new ArrayList<>();
        for (UserOrganizationDTO dto : list) {
            String currentUsername = SecurityUtils.getCurrentUsername();
            if (dto.getUsername().equals(currentUsername)) {
                throw new RuntimeException("不能将自己添加到组织");
            }
            User user = getUserByUsername(dto.getUsername());
            if (user == null) {
                throw new RuntimeException(dto.getUsername() + "：用户不存在");
            }
            // 查询角色信息是否存在，不能修改为超级管理员
            Role role = roleMapper.selectById(dto.getRoleId());
            if (role == null || role.getId() == 1L) {
                throw new RuntimeException("角色不存在或不能使用该角色");
            }

            // 查询用户是否已在组织中
            LambdaQueryWrapper<UserOrganization> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(UserOrganization::getUserId, user.getId());
            queryWrapper.eq(UserOrganization::getOrgId, SecurityUtils.getCurrentOrgId());
            if (userOrganizationMapper.selectCount(queryWrapper) > 0) {
                throw new RuntimeException(user.getUsername() + "：用户已在组织中，不可重复加入");
            }

            // 创建用户组织关联
            UserOrganization userOrganization = new UserOrganization();
            userOrganization.setUserId(user.getId());
            userOrganization.setOrgId(SecurityUtils.getCurrentOrgId());
            // 创建组织，默认组织加入
            userOrganization.setJoinType("1");
            // 默认管理员角色
            userOrganization.setRoleId(dto.getRoleId());
            userOrganization.setUserOrgName(dto.getUserOrgName() == null ? dto.getUsername() : dto.getUserOrgName());
            userOrganization.setCreateTime(LocalDateTime.now());
            userOrganization.setUpdateTime(LocalDateTime.now());
            userOrgList.add(userOrganization);
        }

        userOrganizationMapper.batchInsert(userOrgList);
    }

    @Override
    public Page<User> listUsers(UserVO userVO) {
//        Page<User> page = new Page<>(pageNum, pageSize);
        Page<User> page = PageResult.buildPage();
        // 创建查询条件，按创建时间倒序排序
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        // 排序
        queryWrapper.orderByDesc(User::getUpdateTime);
        // 查询条件
        queryWrapper.like(StringUtils.isNotBlank(userVO.getQuery()), User::getUsername, userVO.getQuery());
        // 执行分页查询
        // 转换为统一分页结果
        return userMapper.selectPage(page, queryWrapper);
    }
    
    /**
     * 修改密码
     *
     * @param updatePasswordDTO 修改密码信息
     * @return 是否成功
     */
    @Override
    public void updatePassword(UpdatePasswordDTO updatePasswordDTO) {
        // 验证两次密码是否一致
        if (!updatePasswordDTO.getNewPassword().equals(updatePasswordDTO.getConfirmNewPassword())) {
            throw new RuntimeException("两次密码不一致");
        }
        
        // 获取当前登录用户
        User currentUser = SecurityUtils.getCurrentUser();
        
        // 验证旧密码是否正确
        assert currentUser != null;
        if (!passwordEncoder.matches(updatePasswordDTO.getOldPassword(), currentUser.getPassword())) {
            throw new RuntimeException("旧密码不正确");
        }
        
        // 更新密码
        User user = new User();
        user.setId(currentUser.getId());
        user.setPassword(passwordEncoder.encode(updatePasswordDTO.getNewPassword()));
        // 更新数据库
         userMapper.updateById(user);
    }
}